package com.wu.serviceImpl.sys;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wu.base.ApiResponse;
import com.wu.base.ResultUtils;
import com.wu.constants.Constants;
import com.wu.entity.sys.SResourceDo;
import com.wu.entity.sys.SRoleDo;
import com.wu.entity.sys.SRoleResourceDo;
import com.wu.entity.sys.SUserRoleDo;
import com.wu.enums.SystemEnum;
import com.wu.enums.field.FlagEnum;
import com.wu.exception.BusinessException;
import com.wu.mapper.SResourceMapper;
import com.wu.mapper.SRoleMapper;
import com.wu.mapper.SRoleResourceMapper;
import com.wu.mapper.SUserRoleMapper;
import com.wu.pojo.reqeust.BaseRequest;
import com.wu.pojo.reqeust.CommonIdRequest;
import com.wu.pojo.reqeust.CommonIdStatusRequest;
import com.wu.pojo.reqeust.sys.*;
import com.wu.pojo.response.sys.RoleCodeResponse;
import com.wu.pojo.response.sys.RoleListResponse;
import com.wu.pojo.response.sys.RoleUserListResponse;
import com.wu.redis.RedisService;
import com.wu.service.sys.SRoleService;
import com.wu.util.DozerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色表(SRole)表服务实现类
 *
 * @since 2020-12-29 13:20:29
 */
@Service("sRoleService")
public class SRoleServiceImpl extends ServiceImpl<SRoleMapper, SRoleDo> implements SRoleService {
    @Resource
    private SRoleMapper sRoleMapper;
    @Resource
    private SUserRoleMapper sUserRoleMapper;
    @Resource
    private SRoleResourceMapper sRoleResourceMapper;
    @Resource
    private SResourceMapper sResourceMapper;
    @Resource
    private RedisService redisService;

    @Override
    public ApiResponse optionList(BaseRequest request) {
        QueryWrapper<SRoleDo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                .orderByDesc("id");
        List<SRoleDo> sRoleListByName = sRoleMapper.selectList(queryWrapper);
        List<RoleListResponse> roleListResponses = DozerUtil.mapList(sRoleListByName, RoleListResponse.class);
        return ResultUtils.setOk(roleListResponses);
    }

    @Override
    public ApiResponse listRole(ListRoleRequest request) {
        PageHelper.startPage(request.getCurrentPage(), request.getPageSize());
        List<SRoleDo> sRoleListByName = sRoleMapper.getSRoleListByName(request.getRoleName());
        List<RoleListResponse> roleListResponses = new ArrayList<>();
        for (SRoleDo roleDo : sRoleListByName) {
            RoleListResponse roleListResponse = new RoleListResponse();
            roleListResponse.setId(roleDo.getId());
            roleListResponse.setName(roleDo.getName());
            roleListResponse.setNumber(countRoleUser(roleDo.getId()));
            //roleListResponse.setResourceList(sRoleResourceMapper.getResourcesByRoleId(roleDo.getId(), 0));
            roleListResponses.add(roleListResponse);
        }
        return ResultUtils.setOk(roleListResponses, new PageInfo<>(sRoleListByName));
    }

    @Transactional
    @Override
    public ApiResponse edit(UpdateRoleRequest request) {
        String roleName = request.getRoleName();
        Long roleId = request.getRoleId();
        if (StringUtils.isNotBlank(roleName)) {
            int count = sRoleMapper.judgeIsExistRoleName(roleName, roleId);
            if (count > 0) {
                return ResultUtils.setError(SystemEnum.ROLE_EXIST);
            }
        }
        List<Long> resourceIds = request.getResourceIds();
        List<SResourceDo> sResourceDos = sResourceMapper.selectBatchIds(resourceIds);
        if (CollectionUtils.isEmpty(sResourceDos) || sResourceDos.size() < resourceIds.size()) {
            return ResultUtils.setError("所选权限不存在，请刷新后重新选择");
        }
        QueryWrapper<SRoleDo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                .eq("id", roleId);
        SRoleDo roleDo = sRoleMapper.selectOne(queryWrapper);
        if (null == roleDo) {
            return ResultUtils.setError(SystemEnum.DATA_NOT_EXIST);
        }
        roleDo.setName(roleName);
        roleDo.setModifier(request.getCurrentUserId());
        roleDo.setModifyTime(new Date());
        int updateById = sRoleMapper.updateById(roleDo);
        if (updateById < 1) {
            return ResultUtils.setError(SystemEnum.FAILED);
        }
        List<SResourceDo> sResourceByIgnore = sResourceMapper.getSResourceByIgnore(1);
        resourceIds.addAll(sResourceByIgnore.stream().map(SResourceDo::getId).collect(Collectors.toList()));
        resourceIds.removeAll(Collections.singleton(null));

        int i = setRoleResource(resourceIds, request.getCurrentUserId(), request.getRoleId());
        if (i > 0) {
            List<RoleUserListResponse> usersByRoleId = sUserRoleMapper.getUsersByRoleId(request.getRoleId());
            for (RoleUserListResponse roleUser : usersByRoleId) {
                redisService.del(Constants.USER_RESOURCES + roleUser.getId(), Constants.SHIRO_CACHE + Constants.SHIRO_USER_RESOURCES + ":" + roleUser.getId());
            }
        }
        return ResultUtils.setOk();
    }

    @Transactional
    @Override
    public ApiResponse save(SaveRoleRequest request) {
        String roleName = request.getRoleName().trim();
        int count = sRoleMapper.judgeIsExistRoleName(roleName, null);
        if (count > 0) {
            return ResultUtils.setError(SystemEnum.ROLE_EXIST);
        }
        List<Long> resourceIds = request.getResourceIds();
        List<SResourceDo> sResourceDos = sResourceMapper.selectBatchIds(resourceIds);
        if (CollectionUtils.isEmpty(sResourceDos) || sResourceDos.size() < resourceIds.size()) {
            return ResultUtils.setError("所选权限不存在，请刷新后重新选择");
        }
        List<SResourceDo> sResourceByIgnore = sResourceMapper.getSResourceByIgnore(1);
        resourceIds.addAll(sResourceByIgnore.stream().map(SResourceDo::getId).collect(Collectors.toList()));
        resourceIds.removeAll(Collections.singleton(null));
        SRoleDo sRoleDo = new SRoleDo();
        sRoleDo.setName(roleName);
        sRoleDo.setCreater(request.getCurrentUserId());
        sRoleDo.setCreateTime(new Date());
        int i = sRoleMapper.insert(sRoleDo);
        if (i < 1) {
            return ResultUtils.setError(SystemEnum.FAILED);
        }
        setRoleResource(resourceIds, request.getCurrentUserId(), sRoleDo.getId());
        return ResultUtils.setOk();
    }

    @Override
    public ApiResponse onOrOff(CommonIdStatusRequest request) {
        return null;
    }

    @Override
    public ApiResponse deleteRole(CommonIdRequest request) {
        QueryWrapper<SRoleDo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                .eq("id", request.getId());
        SRoleDo roleDo = sRoleMapper.selectOne(queryWrapper);
        if (null == roleDo) {
            return ResultUtils.setError(SystemEnum.DATA_NOT_EXIST);
        }
        if (roleDo.getType() == 1) {
            return ResultUtils.setError("此角色不可删除");
        }
        int i = countRoleUser(request.getId());
        if (i > 0) {
            return ResultUtils.setError("角色正在使用，不可删除");
        }
        roleDo.setFlag(FlagEnum.DELETE.getCode());
        roleDo.setModifier(request.getCurrentUserId());
        roleDo.setModifyTime(new Date());
        int updateById = sRoleMapper.updateById(roleDo);
        if (updateById < 1) {
            return ResultUtils.setError(SystemEnum.FAILED);
        }
        return ResultUtils.setOk();
    }


    @Override
    public ApiResponse editResource(RoleResourceEditRequest request, Long userId) {
        int i = setRoleResource(request.getResourceIds(), userId, request.getRoleId());
        if (i > 0) {
            List<RoleUserListResponse> usersByRoleId = sUserRoleMapper.getUsersByRoleId(request.getRoleId());
            for (RoleUserListResponse roleUser : usersByRoleId) {
                redisService.del(Constants.USER_RESOURCES + roleUser.getId(), Constants.SHIRO_CACHE + Constants.SHIRO_USER_RESOURCES + ":" + roleUser.getId());
            }
        }
        return ResultUtils.setOk();
    }

    @Override
    public ApiResponse getById(CommonIdRequest request) {
        SRoleDo roleDo = sRoleMapper.selectById(request.getId());
        if (null == roleDo || FlagEnum.DELETE.getCode().equals(roleDo.getFlag())) {
            return ResultUtils.setError(SystemEnum.DATA_NOT_EXIST);
        }
        RoleListResponse roleListResponse = DozerUtil.map(roleDo, RoleListResponse.class);
        List<RoleCodeResponse> resourcesByRoleId = sRoleResourceMapper.getResourcesByRoleId(roleDo.getId(), 0);
        roleListResponse.setNumber(resourcesByRoleId.size());
        roleListResponse.setResourceList(resourcesByRoleId);
        return ResultUtils.setOk(roleListResponse);
    }

    @Override
    public ApiResponse roleUserList(RoleUserListRequest request) {
        SRoleDo roleDo = sRoleMapper.selectById(request.getId());
        if (null == roleDo || FlagEnum.DELETE.getCode().equals(roleDo.getFlag())) {
            return ResultUtils.setError(SystemEnum.DATA_NOT_EXIST);
        }
        PageHelper.startPage(request.getCurrentPage(), request.getPageSize());
        List<RoleUserListResponse> usersByRoleId = sUserRoleMapper.getUsersByRoleId(request.getId());
        return ResultUtils.setOk(new PageInfo<>(usersByRoleId));
    }

    private int countRoleUser(Long roleId) {
        QueryWrapper<SUserRoleDo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                .eq("role_id", roleId);
        return sUserRoleMapper.selectCount(queryWrapper);
    }

    private int setRoleResource(List<Long> resourceIds, Long currentUserId, Long roleId) {
        List<Long> updateIds = new ArrayList<>();
        List<Long> insertIds = new ArrayList<>(resourceIds);
        int i = 0;
        if (CollectionUtils.isEmpty(resourceIds)) {
            UpdateWrapper<SRoleResourceDo> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                    .eq("role_id", roleId);
            SRoleResourceDo roleResourceDo = new SRoleResourceDo();
            roleResourceDo.setModifier(currentUserId);
            roleResourceDo.setFlag(FlagEnum.DELETE.getCode());
            roleResourceDo.setModifyTime(new Date());
            sRoleResourceMapper.update(roleResourceDo, updateWrapper);
            i++;
            return i;
        } else {
            QueryWrapper<SRoleResourceDo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                    .eq("role_id", roleId);
            List<SRoleResourceDo> sRoleResourceDos = sRoleResourceMapper.selectList(queryWrapper);
            List<Long> collect = sRoleResourceDos.stream().map(SRoleResourceDo::getResourceId).collect(Collectors.toList());
            updateIds.addAll(collect);
            updateIds.removeAll(insertIds);
            insertIds.removeAll(collect);
        }

        QueryWrapper<SResourceDo> queryCount = new QueryWrapper<>();
        queryCount.eq("flag", FlagEnum.NORMAL.getCode())
                .in("id", resourceIds);
        Integer selectCount = sResourceMapper.selectCount(queryCount);
        if (selectCount != resourceIds.size()) {
            throw new BusinessException(SystemEnum.RESOURCE_NO_EXIST);
        }

        updateIds.removeAll(Collections.singleton(null));
        insertIds.removeAll(Collections.singleton(null));
        if (CollectionUtils.isNotEmpty(updateIds)) {
            UpdateWrapper<SRoleResourceDo> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("flag", FlagEnum.NORMAL.getCode())
                    .in("resource_id", updateIds)
                    .eq("role_id", roleId);
            SRoleResourceDo roleResourceDo = new SRoleResourceDo();
            roleResourceDo.setModifier(currentUserId);
            roleResourceDo.setFlag(FlagEnum.DELETE.getCode());
            roleResourceDo.setModifyTime(new Date());
            int update = sRoleResourceMapper.update(roleResourceDo, updateWrapper);
            if (update < 1) {
                throw new BusinessException(SystemEnum.FAILED);
            }
            i++;
        }
        if (CollectionUtils.isNotEmpty(insertIds)) {
            SRoleResourceDo roleResourceDo = new SRoleResourceDo();
            roleResourceDo.setRoleId(roleId);
            roleResourceDo.setCreater(currentUserId);
            for (Long resourceId : insertIds) {
                roleResourceDo.setResourceId(resourceId);
                int insert = sRoleResourceMapper.insert(roleResourceDo);
                if (insert < 1) {
                    throw new BusinessException(SystemEnum.FAILED);
                }
            }
            i++;
        }
        return i;
    }

}